#include <string>
#include "gles_debug.h"

#include <jni.h>
#include "EGL/egl.h"
#include "GLES3/gl3.h"
#include <android/native_window.h>
#include <android/native_window_jni.h>

#define LOG_TAG "AppDisplay"

#define INIT_FAILED -1
#define INIT_SUCCESS 0

static ANativeWindow* egl_window = nullptr;
static EGLDisplay egl_display = nullptr;
static EGLSurface egl_surface = nullptr;
static EGLContext egl_context = nullptr;

static int InitEgl(JNIEnv *env, jobject surface)
{
    EGLBoolean res;
    // 获取Surface
    egl_window = ANativeWindow_fromSurface(env, surface);
    ASSERT_TRUE_WITH_RETURN_VAL(egl_window != nullptr, INIT_FAILED);
    NDK_LOGD(LOG_TAG, "Successfully obtained ANativeWindow.");

    // EGL初始化
    egl_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    ASSERT_TRUE_WITH_RETURN_VAL(egl_display != EGL_NO_DISPLAY, INIT_FAILED);
    res = eglInitialize(egl_display, nullptr, nullptr);
    ASSERT_TRUE_WITH_RETURN_VAL(res == EGL_TRUE, INIT_FAILED);


    // 配置 EGLSurface
    EGLint attribs[] = {
	    EGL_RED_SIZE, 8,
		EGL_GREEN_SIZE, 8,
		EGL_BLUE_SIZE, 8,
		EGL_ALPHA_SIZE, 8,
		EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
		EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,
		EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER,
		EGL_DEPTH_SIZE, 16,
		EGL_NONE
    };
    EGLConfig config;
    EGLint numConfigs;
    res = eglChooseConfig(egl_display, attribs, &config, 1, &numConfigs);
    ASSERT_TRUE_WITH_RETURN_VAL(res == EGL_TRUE, INIT_FAILED);

    // 创建 EGLContext
    EGLint context_attribs[5] = {
            EGL_CONTEXT_CLIENT_VERSION, 3,
            EGL_NONE
    };
    egl_context = eglCreateContext(egl_display, config, EGL_NO_CONTEXT, context_attribs);
    ASSERT_TRUE_WITH_RETURN_VAL(egl_context != EGL_NO_CONTEXT, INIT_FAILED);

    // 创建 EGLSurface
    egl_surface = eglCreateWindowSurface(egl_display, config, egl_window, nullptr);
    ASSERT_TRUE_WITH_RETURN_VAL(egl_surface != EGL_NO_SURFACE, INIT_FAILED);

    // 设置opengl es 上下文
    res = eglMakeCurrent(egl_display, egl_surface, egl_surface, egl_context);
    ASSERT_TRUE_WITH_RETURN_VAL(res == EGL_TRUE, INIT_FAILED);

    res = eglSwapInterval(egl_display, 1);
    ASSERT_TRUE_WITH_RETURN_VAL(res == EGL_TRUE, INIT_FAILED);

    return INIT_SUCCESS;
}

static void Swap() {
    eglSwapBuffers(egl_display, egl_surface);
}

static void DeInitEgl() {
    // 清理
    EGLBoolean res;

	if (egl_display != EGL_NO_DISPLAY) {
		res = eglMakeCurrent(egl_display, EGL_NO_SURFACE,
					EGL_NO_SURFACE, EGL_NO_CONTEXT);
		CHECK(res == EGL_TRUE);
	}

	if (egl_display != EGL_NO_DISPLAY && egl_context != EGL_NO_CONTEXT) {
		res = eglDestroyContext(egl_display, egl_context);
		CHECK(res == EGL_TRUE);
	}

	if (egl_display != EGL_NO_DISPLAY && egl_surface != EGL_NO_SURFACE) {
		res = eglDestroySurface(egl_display, egl_surface);
		CHECK(res == EGL_TRUE);
	}

	if (egl_display != EGL_NO_DISPLAY) {
		res = eglTerminate(egl_display);
		CHECK(res == EGL_TRUE);
	}

    if(egl_window != nullptr){
        ANativeWindow_release(egl_window);
        egl_window = nullptr;
    }
}


extern "C"
JNIEXPORT void JNICALL Java_com_example_jnivxbuffer_AppDisplay_appEglOpenWindow(JNIEnv* env, jobject activity, jobject surface) {

    NDK_LOGI(LOG_TAG, "appEglOpenWindow()");

    InitEgl(env, surface);
}

extern "C"
JNIEXPORT void JNICALL Java_com_example_jnivxbuffer_AppDisplay_appEglCloseWindow(JNIEnv* env, jobject activity) {

    NDK_LOGI(LOG_TAG, "appEglCloseWindow()");

    DeInitEgl();
}

extern "C"
JNIEXPORT void JNICALL Java_com_example_jnivxbuffer_AppDisplay_appEglSwap(JNIEnv* env, jobject activity) {

    NDK_LOGI(LOG_TAG, "appEglSwap()");

    EGLBoolean res = eglSwapBuffers(egl_display, egl_surface);
    CHECK(res == EGL_TRUE);
}
